Firestore rules testing on a custom port
When working with Firebase, it is possible to emulate Firestore, and other Firebase services, on your local machine, so that you do not need to be connected to your production project, and, more importantly, you do not risk to change or delete data used in production.
In some situation you need to run the Firebase emulators on a different port than the default one.
You can do that by setting the port in firebase.json
:
{
"firestore": {
"rules": "firestore.rules",
"indexes": "firestore.indexes.json"
},
"emulators": {
"firestore": {
"port": 65535
}
}
}
then, in your app, you need to set the host in your Firestore.instance.settings
to localhost:65535
, and sslEnabled: false
.
Firestore tests will not run
Unit testing of the Firestore security rules should be done locally, because, as Firebase guru Todd Kerpelman explains in this video, they are faster, safer, and cheaper:
What is not explained, however, is how to deal with custom configurations.
If you follow the video with Firestore running on a non-default port, you encounter this error:
Could not reach Cloud Firestore backend. Connection failed 1 times. Most recent error: FirebaseError: [code=unavailable]: 14 UNAVAILABLE: No connection established
This typically indicates that your device does not have a healthy Internet connection at the moment. The client will operate in offline mode until it is able to successfully connect to the backend.
The solution
The explanation in the error message is not really helpful. In fact the problem is that you need to set up your tests to connect to your emulator:
describe("Our social app", () => {
it("Can read items in the read-only collection", () => {
const db = firebase.initializeTestApp({ projectId: MY_PROJECT_ID }).firestore()
db.settings({ host: "localhost:65535", ssl: false });
const testDoc = db.collection("readonly").doc("testDoc");
qfirebase.assertSucceeds(testDoc.get());
});
});
Cleaning the database when tests are finished
At the end of the tests, or even at the beginning of each test, you should clean the database. This can be done with
firebase.clearFirestoreData({projectId: MY_PROJECT_ID});
The problem is that this call tries to clear the data in the Firestore emulator on the default port, givin the error
connect ECONNREFUSED 127.0.0.1:8080
At this moment it is not possible to provide a port number to clearFirestoreData
, so it is not possible to use that function to clear your local emulated Firestore.
The only solution is to manually remove the created data using the SDK:
after(async () => {
const dbAdmin = firebase.initializeAdminApp({ projectId: MY_PROJECT_ID }).firestore();
dbAdmin.settings({ host: "localhost:65535", ssl: false });
await dbAdmin.collection("posts").doc("public_post").delete();
await dbAdmin.collection("posts").doc("private_post").delete();
})
Just remember to delete document subcollections, if you created any, because they will not be deleted by deleting the parent document.
Leave a comment